#ifndef CVX_CONCENTRIC_H
#define CVX_CONCENTRIC_H 1

#include "cvxImage.h"
#include "cvxMarker.h"
#include "cvxBoard.h"


//marker concentric circle board
class CvxMarkerCCBoard
{
public:
	CvxMarkerCCBoard();
	~CvxMarkerCCBoard();

	bool SetConfigure(const CvSize &size, const float unitLength);
	bool FindCorners(const IplImage *image, bool isTracking, 
		const vector<CvxMarker>& preMarkers,
		vector<CvxMarker> &curMarker,
		vector<Point2f> &pts2d, vector<Point3f> &pts3d)const;

	bool FindCorners(const IplImage *image, bool isTracking, const vector<CvxMarker>& preMarkers, 
		vector<CvxMarker> &curMarker, vector<Point2f> &pts2d)const;

	bool GetInsidePoints(const IplImage *image, vector<Point2f> &extremeCorners,
		vector<Point2f> &pts2d, vector<Point3f> &pts3d)const;

	void DrawCorners(const IplImage *image, const vector<Point2f> &pts)const;

	float GetUnitLength(void)const
	{
		return m_unitLength;
	}
	CvSize GetPatternSize(void)const
	{
		return m_size;
	}
	void Get3Dpts(vector<Point3f> &pts3d) const
	{
		assert(m_pts3d.size() == m_size.width * m_size.height);
		pts3d = m_pts3d;
	}

private:
	CvSize m_size;
	float  m_unitLength;  //distance between near two circle centers
	CvSize m_markerSize; 
	CvSize m_markerOffset;
	vector<Point3f> m_pts3d;
	vector<Point2f> m_pts2d;   //z == 0
};

/************************************************************************/
/* 
CvxMarkerInsiderChessboard
marker position is inside chessboard of (1, 1)(w-2,1)(w-2,h-2)(1,h-2)
*/
/************************************************************************/

class CvxMarkerInsiderChessboard : public CvxBoard
{
public:
	CvxMarkerInsiderChessboard();
	~CvxMarkerInsiderChessboard();

	bool SetConfigure(const CvSize &size, const float unitLength);
	bool SetMarkerCorners(float markerLength);  //unitLength * 1.5 / 1.75

	bool FindCorners(const IplImage *image, bool isTracking, const vector<CvxMarker>& preMarkers, vector<CvxMarker> &curMarker,
		vector<Point2f> &pts2d, vector<Point3f> &pts3d)const;

	bool FindCorners(const IplImage *image, bool isTracking, const vector<CvxMarker>& preMarkers, 
		vector<CvxMarker> &curMarker, vector<Point2f> &pts2d)const;

	bool GetInsidePoints(const IplImage *image, vector<Point2f> &extremeCorners, 
		vector<Point2f> &pts2d, vector<Point3f> &pts3d)const;

	void DrawCorners(const IplImage *image, const vector<Point2f> &pts)const;

	float GetUnitLength(void)const;
	CvSize GetPatternSize(void)const;
	void Get3Dpts(vector<Point3f> &pts3d) const;


	vector<Point3f> m_markerCorners3d;    // 4 * 4

private:
	CvSize m_size;
	float  m_squareLen;
	vector<Point2f> m_markerCenters;    //physical position of marker centers
	vector<Point3f> m_pts3d;
	vector<Point2f> m_pts2d;            //z == 0	
};


class CvxConcentric
{
public:

	//detect concentric center from an gray image, inRatio is used to evaluate precision 
	static bool detect(IplImage *grayImage, const Point2f &seedPt, Point2f &center, 
		               float &ratio, bool fixRatio, const float inRatio, const float ratioThreshold);

private:
	static bool GetLinePoints(IplImage *grayImage, const Point2f &midP, int sita,
								bool &xDominate, double &startXorY, double &lineSlop,
								vector<unsigned char> & lineData);

	//get subpixel position of max, min value Index from 1 D array,
	//assume it just has one max min value in the array
	static void minMaxIdx1DSubPixel(const Mat &inMat, double &minPos, double &maxPos);

	//get middle points coordinate (x axis or y axis) from coordinates of four concentric circles
	static bool GetMiddlePoints(const double leftMaxp, const double leftMinp, 
								const double rightMaxp, const double rightMinp, 							 
								double &midPx, float &ratio);
};

class ConcentriCheckerBoard
{
public:
	CvSize _size;          //16 * 9
	float  _unitLength;    //physical length between concentric circles

	vector<Point2f> _centerPts;
	vector<vector<Point2f>> _boundrayPts;  //every center has four boundary points
	vector<Point2f> _seedPts;              //every center has one seeds

	vector<Point2f> _markerPos;                 //marker center position
	vector<Point2f> _markerCorners;             //every marker has four corners,

	ConcentriCheckerBoard(CvSize size, CvSize markerSize, CvSize markerOffset, float unitLength);	

	//from physical position to image position
	void HomographyMap(const Mat &H, vector<Point2f> &centerPts,	
					   vector<Point2f> &seedPts, vector<vector<Point2f>> &boundary) const;

private:
	float _inCircleRatio;  //ratio < 1.0, unit length = 1.0;
	float _outCircleRatio; //ratio < 1.0
};

bool cvxFindConcentriBoard(IplImage * grayImage, const CvSize size, const CvSize markerSize, 
						   const CvSize markerOffset, const float unitLength, vector<Point2f> &pts,
						   vector<bool> &mask,
						   bool useMarkerTracking,
						   const vector<CvxMarker> & preMarkers, //markers in previous frames
						   vector<CvxMarker> &curMarkers); 
						     


#endif